package com.beiding.jsonanalyzer.querylink;

import com.beiding.jsonanalyzer.analyze.ValueUtils;
import com.beiding.jsonanalyzer.flow.*;
import com.beiding.jsonanalyzer.flow.flowevents.BatchEndEvent;
import com.beiding.jsonanalyzer.flow.flowevents.BatchStartEvent;
import com.beiding.jsonanalyzer.flow.flowevents.DataNodeEvent;
import com.beiding.jsonanalyzer.visit.VisitAble;
import com.beiding.jsonanalyzer.visit.VisitorAdapter;

import java.util.*;

/**
 * 分支节点
 *
 * @author 丁常磊
 * @date 2022/5/11 17:27
 */

public class BranchQueryLinkNode<W extends ValueNode> extends QueryLinkNodeAdapter<W> {


    /**
     * 分支依据链
     */
    private ComputeResource computeResource;

    private Object key;

    public BranchQueryLinkNode(QueryLinkNode<W> pre, Object key, ComputeResource computeResource) {
        super(pre);
        this.computeResource = computeResource;
        this.key = key;
    }

    @Override
    protected VisitAble<BranchNode<W>> doExec(VisitAble<BranchNode<W>> preResult) {


        return nextBranchAccepter -> {

            VisitAble<BranchNode<W>> last = preResult;

            last = branchForOneKey(last, key);

            //对最后一级增加一个空白代理
            last.visit(new VisitorAdapter<>(nextBranchAccepter));

        };

    }

    /**
     * 用于逐层嵌套
     *
     * @param preResult
     * @param key
     * @return
     */
    private VisitAble<BranchNode<W>> branchForOneKey(VisitAble<BranchNode<W>> preResult, Object key) {
        return nextBranchAccepter -> {

            //对每个前置节点执行链式行为
            preResult.visit(branch -> {

                //如果设置了计算源就使用设置的计算源,否则就继承前置

                ComputeResource cpm = computeResource;

                if (cpm == null) {
                    cpm = branch.getBranch().getComputeResource();
                }

                //给当前流创建一个网关
                BranchGateway<W> branchGateway = new BranchGateway<>(branch.getBranch(), cpm, branch.getBranch().getBranchReferLink(), branch.getBranch().getValueNodeFactory());

                List<FlowEvent<W>> events = new ArrayList<>();

                branch.onDataEvent(FlushEvent.type(), event -> {

                    //所有的事件一定都是串行执行的,因此不用担心处理时数据被修改
                    Collection<BranchNode<W>> allBranch = branchGateway.getAllBranch();

                    //没有任务直接结束
                    if (allBranch.size() == 0) {
                        event.getCallback().run();
                        return;
                    }

                    //线程安全的set
                    Set<BranchNode<W>> all = Collections.synchronizedSet(new HashSet<>(allBranch));

                    //记录一下当前产生的所有的分支
                    for (BranchNode<W> wBranchNode : allBranch) {
                        //对每一个进行刷新操作
                        wBranchNode.flush(() -> {
                            //筛选完成后移除掉当前分支对象
                            all.remove(wBranchNode);
                            //所有的后续节点都执行完了刷新操作
                            if (all.size() == 0) {
                                //再反馈当前节点的刷新
                                branchGateway.runAfterClear(event.getCallback());
                            }
                        });
                    }

                });

                branch.onDataEvent(BatchStartEvent.eventType(), event -> {

                    //批开始事件
                    events.add(event);

                    for (BranchNode<W> br : branchGateway.getAllBranch()) {
                        br.signDataEvent(event);
                    }
                });

                branch.onDataEvent(BatchEndEvent.eventType(), event -> {
                    for (BranchNode<W> br : branchGateway.getAllBranch()) {
                        br.signDataEvent(event);
                    }

                    //清理 清理掉后继节点 防止oom
                    branchGateway.clear();
                    //保存的事件也清理
                    events.clear();
                });

                branch.onDataEvent(DataNodeEvent.eventType(), event -> {
                    //分组引用
                    Object refer = ValueUtils.execExpression(event.getData().get(), key, Object.class);
                    BranchGateway<W>.BranchResult branchResult = branchGateway.getOneBranch(key, refer);
                    //如果是个新的流程分支
                    if (branchResult.isNewBranch()) {
                        //传递给下级
                        //把第一个分支传递出去
                        nextBranchAccepter.onNode(branchResult.getBranchNode());

                        //将保存的事件写入
                        for (FlowEvent<W> et : events) {
                            branchResult.getBranchNode().signDataEvent(et);
                        }

                    }

                    //放入数据节点
                    branchResult.getBranchNode().signDataEvent(new DataNodeEvent<>(event.getData()));

                });

            });


        };
    }


}
